/**
 * 
 */
package com.tvshows.structure.patterns;

import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Hashtable;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.log4j.Logger;
import org.w3c.dom.CharacterData;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.tvshows.structure.log.LoggingTreatment;

/**
 * @author Tangi Midy
 */
public class UrlConstructor
{

    private String urlToAdd = null, urlToTest, title = null;

    private DocumentBuilder builder;

    private Hashtable<String, String> feeds;

    private URL feedUrl;

    private Document doc;

    private NodeList nodes;

    private String[] cutUrl = PatternShowEnumeration.listPatternConstructor[0].split( ";" );;

    private final Logger logger = Logger.getLogger( UrlConstructor.class );

    private boolean broken;

    /**
     * Construct a feed from a url
     * 
     * @param url the url to apply
     */
    private void constructFeed( String url )
    {
        try
        {
            feedUrl = new URL( url );
            builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            doc = builder.parse( feedUrl.openStream() );
            nodes = doc.getElementsByTagName( "item" );
        }
        catch ( Exception e )
        {
            LoggingTreatment.getInstance().logError( logger, e.getLocalizedMessage() );
        }
    }

    /**
     * Returns one feed for the show
     * 
     * @param paramName name of the show
     * @param paramSeason season number
     * @param paramEpisode episode number
     */
    public void getFeed( String paramName, String paramSeason, String paramEpisode )
    {
        urlToAdd = null;
        urlToTest = null;
        nodes = null;
        urlToTest = cutUrl[0] + paramName + cutUrl[1] + paramSeason + cutUrl[2] + paramEpisode + cutUrl[3];
        constructFeed( urlToTest );
        if ( nodes != null && nodes.getLength() > 0 )
        {
            Element element = (Element) nodes.item( 0 );

            if ( getElementValue( element, "title" ).contains( paramName.trim().replace( "+", " " ) )
                && getElementValue( element, "title" ).contains( paramSeason )
                && getElementValue( element, "title" ).contains( paramEpisode ) )
            {
                urlToAdd = getElementValue( element, "link" );
                title = getElementValue( element, "title" );
            }
        }
    }

    /**
     * Retrieves the Rss feeds
     * 
     * @param paramName name of the feed
     * @return hashmap of feeds
     */
    public Hashtable<String, String> getFeeds( String paramName )
    {
        urlToAdd = null;
        feeds = null;
        urlToTest = null;
        nodes = null;
        urlToTest = "http://torrentz.eu/feed?q=" + paramName;
        constructFeed( urlToTest );
        if ( nodes != null && nodes.getLength() > 0 )
        {
            feeds = new Hashtable<String, String>();
            Element element = null;
            for ( int i = 0; i < nodes.getLength(); i++ )
            {
                element = (Element) nodes.item( i );
                feeds.put( getElementValue( element, "title" ) + "  " + getElementValue( element, "category" ),
                    getElementValue( element, "link" ) );
            }
        }
        return feeds;
    }

    /**
     * Gets the value of the Element
     * 
     * @param parent the parent element
     * @param label the label tag
     * @return Datas or empty string
     */
    private String getElementValue( Element parent, String label )
    {
        return getCharacterDataFromElement( (Element) parent.getElementsByTagName( label ).item( 0 ) );
    }

    /**
     * extract character data from xml Element
     * 
     * @param e the element to parse
     * @return datas or empty string
     */
    private String getCharacterDataFromElement( Element e )
    {
        try
        {
            Node child = e.getFirstChild();
            if ( child instanceof CharacterData )
            {
                CharacterData cd = (CharacterData) child;
                return cd.getData();
            }
        }
        catch ( Exception ex )
        {
            LoggingTreatment.getInstance().logError( logger, ex.getLocalizedMessage() );
        }
        return "";
    }

    /**
     * Tests the correctness of the URL
     * 
     * @param url the url to test
     * @return url==correct?
     */
    private boolean testUrl( String url )
    {
        try
        {
            HttpURLConnection.setFollowRedirects( true );
            HttpURLConnection con = (HttpURLConnection) new URL( url ).openConnection();

            con.setRequestMethod( "HEAD" );
            return ( con.getResponseCode() == HttpURLConnection.HTTP_OK );
        }
        catch ( Exception e )
        {
            LoggingTreatment.getInstance().logError( logger, e.getLocalizedMessage() );
        }
        return false;
    }

    /**
     * Constructs the final url
     * 
     * @param paramName name of the show
     * @param paramSeason season
     * @param paramEpisode episode
     */
    public void constructUrl( String paramName, String paramSeason, String paramEpisode )
    {

        this.broken = false;
        // premier type de pattern
        cutUrl = PatternShowEnumeration.listPatternConstructor[0].split( ";" );
        urlToAdd = null;
        String urlToTest = cutUrl[0] + paramName + cutUrl[1] + paramSeason + cutUrl[2] + paramEpisode + cutUrl[3];

        // Boucle sur les urls
        boucleUrls( urlToTest, paramName );

        if ( !broken )
        {
            // Le deuxième type de pattern
            cutUrl = PatternShowEnumeration.listPatternConstructor[1].split( ";" );
            urlToAdd = null;
            urlToTest =
                cutUrl[0] + paramName + cutUrl[1] + paramSeason.substring( 1 ) + cutUrl[2] + paramEpisode + cutUrl[3];

            boucleUrls( urlToTest, paramName );
        }

    }

    /**
     * Tests the urls
     * 
     * @param urlToTest the url to map
     */
    private void boucleUrls( String urlToTest, String paramName )
    {
        for ( String rip : PatternShowEnumeration.listNameRip )
        {
            if ( testUrl( urlToTest.replace( " ", "." ) + rip + cutUrl[4] ) )
            {
                urlToAdd = urlToTest + rip + cutUrl[4];
                this.title = paramName;
                this.broken = true;
                break;
            }
        }
    }

    /**
     * @return the urlToAdd
     */
    public String getUrlToAdd()
    {
        return urlToAdd;
    }

    /**
     * @return the title
     */
    public String getTitle()
    {
        return title;
    }
}
